/**
 * PANDA 3D SOFTWARE
 * Copyright (c) Carnegie Mellon University.  All rights reserved.
 *
 * All use of this software is subject to the terms of the revised BSD
 * license.  You should have received a copy of this license along
 * with this source code in a file named "LICENSE."
 *
 * @file collisionSolid.I
 * @author drose
 * @date 2000-06-27
 */

/**
 * Sets the current state of the 'tangible' flag.  Set this true to make the
 * solid tangible, so that a CollisionHandlerPusher will not allow another
 * object to intersect it, or false to make it intangible, so that a
 * CollisionHandlerPusher will ignore it except to throw an event.
 */
INLINE void CollisionSolid::
set_tangible(bool tangible) {
  LightMutexHolder holder(_lock);
  if (tangible) {
    _flags |= F_tangible;
  } else {
    _flags &= ~F_tangible;
  }
  _flags |= F_viz_geom_stale;
}

/**
 * Returns whether the solid is considered 'tangible' or not.  An intangible
 * solid has no effect in a CollisionHandlerPusher (except to throw an event);
 * it's useful for defining 'trigger' planes and spheres, that cause an effect
 * when passed through.
 */
INLINE bool CollisionSolid::
is_tangible() const {
  LightMutexHolder holder(_lock);
  return do_is_tangible();
}

/**
 * Records a false normal for this CollisionSolid that will be reported by the
 * collision system with all collisions into it, instead of its actual normal.
 * This is useful as a workaround for the problem of an avatar wanting to
 * stand on a sloping ground; by storing a false normal, the ground appears to
 * be perfectly level, and the avatar does not tend to slide down it.
 */
INLINE void CollisionSolid::
set_effective_normal(const LVector3 &effective_normal) {
  LightMutexHolder holder(_lock);
  _effective_normal = effective_normal;
  _flags |= F_effective_normal;
}

/**
 * Removes the normal previously set by set_effective_normal().
 */
INLINE void CollisionSolid::
clear_effective_normal() {
  LightMutexHolder holder(_lock);
  _flags &= ~F_effective_normal;
}

/**
 * Returns true if a special normal was set by set_effective_normal(), false
 * otherwise.
 */
INLINE bool CollisionSolid::
has_effective_normal() const {
  LightMutexHolder holder(_lock);
  return do_has_effective_normal();
}

/**
 * Returns the normal that was set by set_effective_normal().  It is an error
 * to call this unless has_effective_normal() returns true.
 */
INLINE const LVector3 &CollisionSolid::
get_effective_normal() const {
  LightMutexHolder holder(_lock);
  nassertr(do_has_effective_normal(), LVector3::zero());
  return _effective_normal;
}

/**
 * This is only meaningful for CollisionSolids that will be added to a
 * traverser as colliders.  It is normally true, but if set false, it means
 * that this particular solid does not care about the "effective" normal of
 * other solids it meets, but rather always uses the true normal.
 */
INLINE void CollisionSolid::
set_respect_effective_normal(bool respect_effective_normal) {
  LightMutexHolder holder(_lock);
  // For historical reasons, the bit we store is the opposite of the bool flag
  // we present.
  if (respect_effective_normal) {
    _flags &= ~F_ignore_effective_normal;
  } else {
    _flags |= F_ignore_effective_normal;
  }
}

/**
 * See set_respect_effective_normal().
 */
INLINE bool CollisionSolid::
get_respect_effective_normal() const {
  LightMutexHolder holder(_lock);
  return (_flags & F_ignore_effective_normal) == 0;
}

/**
 * Returns whether the solid is considered 'tangible' or not.  Assumes the
 * lock is already held.
 */
INLINE bool CollisionSolid::
do_is_tangible() const {
  return (_flags & F_tangible) != 0;
}

/**
 * Returns true if a special normal was set by set_effective_normal(), false
 * otherwise.  Assumes the lock is already held.
 */
INLINE bool CollisionSolid::
do_has_effective_normal() const {
  return respect_effective_normal && (_flags & F_effective_normal) != 0;
}

/**
 * Should be called by a derived class to mark the internal bounding volume
 * stale, so that recompute_internal_bounds() will be called when the bounding
 * volume is next requested.
 */
INLINE void CollisionSolid::
mark_internal_bounds_stale() {
  LightMutexHolder holder(_lock);
  _flags |= F_internal_bounds_stale;
}

/**
 * Called internally when the visualization may have been compromised by some
 * change to internal state and will need to be recomputed the next time it is
 * rendered.
 */
INLINE void CollisionSolid::
mark_viz_stale() {
  LightMutexHolder holder(_lock);
  _flags |= F_viz_geom_stale;
}
